/*
 * @Author: Dorange.Wang
 * @Date: 2021-07-06 19:18:21
 * @LastEditors: your name
 * @LastEditTime: 2021-07-20 11:33:58
 * @Description: file content
 */
import axios from 'axios'
import store from '@/store'
import storage from 'store2'
// import notification from 'ant-design-vue/es/notification'
// import { VueAxios } from './axios'
import { 
  APP_TOKEN,
  APP_PREVIEW,
  APP_UNIQUE,
  DOMAIN_SUFFIX
 } from '@/utils/const'
// import { i18nRender } from '@/locales'
import apiConfig, { baseURL } from '@/config/api.config'

/* eslint-disable */

const CancelToken = axios.CancelToken
// 请求列表
const requests = []
// 取消列表
const sources = {}

// 创建 axios 实例
const instance = axios.create({
  // API 请求的默认前缀
  baseURL,
  timeout: 20000, // 请求超时时间
  headers: {
    [APP_PREVIEW]: true,
    [DOMAIN_SUFFIX]: apiConfig.domainSuffix
  }
})

/**
 * 将一个请求转换成对应的字符串，用于比较多个请求是否相同，这里下定义：
 * 当两个请求的method、完整url、全部参数均相同时，则认为这两个请求为“相同请求”
 * @param {*} config
 */
const genUniqueRequest = config => {
  let argStr = ''
  if (!!config && Object.prototype.hasOwnProperty.call(config,'params')) {
    argStr = JSON.stringify(config.params)
  } else if (!!config && Object.prototype.hasOwnProperty.call(config,'data')) {
    if (config.data instanceof FormData) {
      // 如果是formData则需要这样处理
      argStr = JSON.stringify(Object.fromEntries(config.data))
    } else {
      argStr = JSON.stringify(config.data)
    }
  }
  return `${config.method}_${config.baseURL}${config.url}_${argStr}`
}

/**
 * 将请求添加至列表
 * @param {*} config
 */
const addRequest = config => {
  const request = genUniqueRequest(config)
  console.log('request',request)
  // 如果已经有cancelToken就不要新加了，也不加进requests
  if (!config.cancelToken) {
    config.cancelToken = new CancelToken(cancel => {
      sources[request] = cancel
    })
    // 1.判断请求是否已存在请求列表，避免重复请求，将当前请求添加进请求列表数组；
    if (requests.includes(request)) {
      console.log(requests, request)
      sources[request]('取消重复请求：' + JSON.stringify(request))
    } else {
      requests.push(request)
      // 2. 如果有全局loading状态，在这里置为true
      // todo
    }
  } else {
    console.log(config, 'cancelToken已存在 ')
  }
}

/**
 * 从列表中移除请求
 * @param {*} config
 */
const deleteRequest = config => {
  // 1.将当前请求中请求列表中删除
  const request = genUniqueRequest(config)
  requests.splice(
    requests.findIndex(item => item === request),
    1
  )
  // 2.当请求列表为空时，如果有全局loading状态，在这里置为false
  if (requests.length === 0) {
    // todo
  }
}

/**
 * 异常拦截处理器
 * @param {*} error 
 * @returns 
 */
const errorHandler = error => {
  if (error.response) {
    // const data = error.response.data
    const {status} = error.response

    if (status === 401) {
      cancelAllRequest()
      store.dispatch('userLogout')
    }

    if (error.response.status === 403) {
      cancelAllRequest()
      // notification.error({
      //   message: i18nRender('common.error'),
      //   description: i18nRender(data.message)
      // })
    }

    if (error.response.status === 423) {
      cancelAllRequest()
      // notification.error({
      //   message: i18nRender('common.error'),
      //   description: i18nRender('common.loginAnotherDevice')
      // })
      // store.dispatch('Logout').then(() => {
      //   setTimeout(() => {
      //     window.location.reload()
      //   }, 1500)
      // })
    }
  } else {
    if (axios.isCancel(error)) {
      // error.selfCancel = true
    } else if (error.message.indexOf('timeout') > -1) {
      // notification.error({
      //   message: i18nRender('common.error'),
      //   description: i18nRender('common.connectionTimeOut')
      // })
      deleteRequest(error.config)
    } else if (error.message.indexOf('取消') === -1) {
      // 不包含取消请求
      // notification.error({
      //   message: i18nRender('common.error'),
      //   description: error.message
      // })
      deleteRequest(error.config)
    }
  }
  return Promise.reject(error)
}

/**
 * 取消所有请求
 */
const cancelAllRequest = function () {
  requests.splice(0, requests.length)
  for (const prop in sources) {
    if (Object.prototype.hasOwnProperty.call(sources,prop)) {
      sources[prop]('cancelAllRequest ' + JSON.stringify(prop))
    }
  }
}

/**
 * 请求拦截器
 */
 instance.interceptors.request.use(config => {
  // addRequest(config)
  const token = storage.get(APP_TOKEN)
  const unique = storage.session.get(APP_UNIQUE)
  // 如果 token 存在
  // 让每个请求携带自定义 token 请根据实际情况自行修改
  if (token) {
    config.headers[APP_TOKEN] = token
  }
  if(unique){
    config.headers[APP_UNIQUE] = `hm_${unique}`
  }
  return config
}, errorHandler)

/**
 * 响应拦截器
 */
 instance.interceptors.response.use(response => {
  deleteRequest(response.config)

  const data = response.data
  const { responseType } = response.config

  // 针对流数据做单独处理
  if (responseType === 'blob') {
    // 本应返回流数据却返回了application/json，则说明报错，走错误处理分支
    // if (data.type === 'application/json') {
    //   const reader = new FileReader()
    //   reader.onload = e => {
    //     const res = JSON.parse(e.target.result)
    //     const errorMsg = res.message ? i18nRender(res.message) : i18nRender('common.serverError')
    //     notification.error({
    //       message: i18nRender('common.error'),
    //       description: errorMsg
    //     })
    //     return Promise.reject(errorMsg)
    //   }
    //   reader.readAsText(data)
    // } else {
    //   return data
    // }
  } else {
    if (data.code === 0) {
      return data.data
    } else if (data.code === 401) {
      // cancelAllRequest()
      // notification.error({
      //   message: i18nRender('common.error'),
      //   description: i18nRender('common.loginTimeOut')
      // })
      // store.dispatch('Logout').then(() => {
      //   setTimeout(() => {
      //     window.location.reload()
      //   }, 1500)
      // })
    } else {
      // 如果是主动校验的返回，则需要将message抓取并展示到UI对应位置
      // const { headers, responseType } = response.config
      // if ((!!headers && headers.validate && data.code !== -1) || responseType === 'blob') {
      //   return data
      // }
      // const { code } = data
      // const i18nCode = i18nRender(code)
      // const errorMsg = String(code) === String(i18nCode) ? (data.message || i18nRender('common.serverError')) : i18nCode
      // notification.error({
      //   message: i18nRender('common.error'),
      //   description: errorMsg
      // })
      // return Promise.reject(errorMsg)
    }
  }
}, errorHandler)

// const installer = {
//   vm: {},
//   install (Vue) {
//     Vue.use(VueAxios, instance)
//   }
// }

export default instance

export {
  // installer as VueAxios,
  instance as axios,
  cancelAllRequest
}
